﻿using System.Collections;
using System.Collections.Generic;
using Unity.VisualScripting;
using Unity.VisualScripting.FullSerializer;
using UnityEngine;
using static UnityEngine.UI.Image;

public class PuzzleSolver
{
    struct QueueNodeContext
    {
        GameObject ObjectRef;
        ImpulseType State;
    }
    class QueueNode
    {
        public uint StateIndex;
        public List<QueueNodeContext> Contexts;

        public QueueNode(uint InStateIndex)
        {
            StateIndex = InStateIndex;
            Contexts = new List<QueueNodeContext>();
        }
    }

    /// <summary>
    /// 使用一个队列，执行类似广搜的规则求解
    /// </summary>
    /// <param name="MapState"></param>
    /// <param name="RuleSystem"></param>
    public static MapState Solve(MapState MapState, PuzzleRuleSystem RuleSystem, InputType InInputType)
    {
        Debug.Log("--------------------Start Solve--------------------------");

        MapState FrameMapState = (MapState)MapState.Clone();

        SolveStateMachine(ref FrameMapState, RuleSystem, InInputType);
        ExcuteMove(ref FrameMapState);

        Debug.Log("--------------------End Solve--------------------------");
        return FrameMapState;
    }
    /// <summary>
    /// 根据Edge的ActiveType决定怎么判断目前的状态
    /// </summary>
    /// <param name="Node"></param>
    /// <param name="Edge"></param>
    static bool Solve_ConditionCheck(StateMachineNode Node, StateMachineEdge Edge, InputType InInputType)
    {
        switch (Edge.ActiveType) 
        {
            case EdgeActiveType.None:
                return true;
            case EdgeActiveType.Action:
                break;
            case EdgeActiveType.Up:
                return InInputType == InputType.Up;
            case EdgeActiveType.Left:
                return InInputType == InputType.Left;
            case EdgeActiveType.Down:
                return InInputType == InputType.Down;
            case EdgeActiveType.Right:
                return InInputType == InputType.Right;
            case EdgeActiveType.Rule: // 直接通过还是说要再次检查条件
                return true;
            case EdgeActiveType.Match: // 检测是否与下一个节点条件Match
                return true;
        }

        return false;
    }

    static void ExcuteMove(ref MapState FrameMapState)
    {
        for (int i = 0; i < FrameMapState.SizeY; i++)
        {
            for (int j = 0; j < FrameMapState.SizeX; j++)
            {
                Vector2Int Origin = new Vector2Int(j, i);

                var MapElement = FrameMapState.Map[Origin.y * FrameMapState.SizeX + Origin.x];
                List<MapCellRuntimeObject> DeleteElements = new List<MapCellRuntimeObject>();

                foreach (var ObjectElement in MapElement.Objects)
                {
                    // 执行过就不动了
                    if ((ObjectElement.Impulse & ImpulseType.FinishImpulse) > 0)
                    {
                        continue;
                    }
                    // 静止也不动了
                    if ((ObjectElement.Impulse & ImpulseType.Stop) > 0)
                    {
                        continue;
                    }
                    // 没操作过也不动
                    if (ObjectElement.Impulse == ImpulseType.None)
                    {
                        continue;
                    }

                    // 检查边界
                    Vector2Int SearchDir = new Vector2Int(0, 0);
                    if (ObjectElement.Impulse == ImpulseType.Right)
                    {
                        SearchDir.x = 1;
                    }
                    if (ObjectElement.Impulse == ImpulseType.Left)
                    {
                        SearchDir.x = -1;
                    }
                    if (ObjectElement.Impulse == ImpulseType.Up)
                    {
                        SearchDir.y = -1;
                    }
                    if (ObjectElement.Impulse == ImpulseType.Down)
                    {
                        SearchDir.y = 1;
                    }
                    Vector2Int End = Origin + SearchDir;
                    if (End.x < 0 || End.x >= FrameMapState.SizeX || End.y < 0 || End.y >= FrameMapState.SizeY) { ObjectElement.Impulse = ImpulseType.FinishImpulse; continue; }
                    // 移动
                    Debug.Log(ObjectElement.Name + "_" + ObjectElement.Impulse);
                    var ToMapElement = FrameMapState.Map[End.y * FrameMapState.SizeX + End.x];
                    ObjectElement.Impulse = ImpulseType.FinishImpulse;
                    ToMapElement.Objects.Add(ObjectElement);
                    DeleteElements.Add(ObjectElement);
                }

                foreach (var ObjectElement in DeleteElements)
                {
                    MapElement.Objects.Remove(ObjectElement);
                }
            }
        }
    }
    static void SolveStateMachine(ref MapState FrameMapState, PuzzleRuleSystem RuleSystem, InputType InInputType)
    {
        Queue<QueueNode> SolveNode = new Queue<QueueNode>();
        SolveNode.Enqueue(new QueueNode(0)); // 理论上应该入栈RootNode

        uint SolveLimit = 1000;
        uint SolveStep = 0;
        // 循环进行状态机移动
        while (SolveNode.Count > 0 && SolveStep < SolveLimit)
        {
            SolveStep += 1;

            var QueueNode = SolveNode.Dequeue();
            var StateFromNode = RuleSystem.StateMachine.Nodes[RuleSystem.StateMachine.NodeIndices[(int)QueueNode.StateIndex]];

            Debug.Log(StateFromNode.RuleSegment.ToMermaid());

            MapState SegmentMapState = (MapState)FrameMapState.Clone();

            foreach (var StateEdge in StateFromNode.Edges)
            {
                //Debug.Log(StateEdge.FromNode + "->" + StateEdge.ToNode);
                if (!Solve_ConditionCheck(StateFromNode, StateEdge, InInputType))
                {
                    continue;
                }
                //Solve_Internal();
                // 条件检查成功，要去查找模式匹配
                QueueNode NextQueueNode = new QueueNode(StateEdge.ToNode);
                var StateToNode = RuleSystem.StateMachine.Nodes[RuleSystem.StateMachine.NodeIndices[(int)StateEdge.ToNode]];
                
                // 三种状态转移
                // 激活
                // 从From到To的状态转移
                // None激活
                if (StateEdge.ActiveType == EdgeActiveType.None || StateEdge.ActiveType == EdgeActiveType.Match)
                {
                    // 目前是无条件的激活，理论上是一个激活
                    var DebugLog = "";
                    DebugLog = "    " + StateFromNode.RuleSegment.ToMermaid() + " --> " + StateToNode.RuleSegment.ToMermaid();
                    switch (StateEdge.ActiveType)
                    {
                        case EdgeActiveType.Rule: DebugLog += ": Rule"; break;
                        case EdgeActiveType.Match: DebugLog += ": Match"; break;
                        case EdgeActiveType.Up: DebugLog += ": W"; break;
                        case EdgeActiveType.Down: DebugLog += ": S"; break;
                        case EdgeActiveType.Left: DebugLog += ": A"; break;
                        case EdgeActiveType.Right: DebugLog += ": D"; break;
                        case EdgeActiveType.None: DebugLog += ": None"; break;
                    }
                    Debug.Log(DebugLog);
                    SolveNode.Enqueue(NextQueueNode);
                }
                else if (StateEdge.ActiveType == EdgeActiveType.Action || StateEdge.ActiveType == EdgeActiveType.Up || StateEdge.ActiveType == EdgeActiveType.Left ||
                    StateEdge.ActiveType == EdgeActiveType.Down || StateEdge.ActiveType == EdgeActiveType.Right || StateEdge.ActiveType == EdgeActiveType.Rule)
                {
                    // 需要匹配的信息放置在StateFromNode.ObjectRefs
                    // 状态查找设置
                    Vector2Int SearchDir = new Vector2Int(0, 0);
                    if (StateFromNode.RuleSegment.Relevance == RelevanceType.Right)
                    {
                        SearchDir.x = 1;
                    }
                    if (StateFromNode.RuleSegment.Relevance == RelevanceType.Left)
                    {
                        SearchDir.x = -1;
                    }
                    if (StateFromNode.RuleSegment.Relevance == RelevanceType.Up)
                    {
                        SearchDir.y = -1;
                    }
                    if (StateFromNode.RuleSegment.Relevance == RelevanceType.Down)
                    {
                        SearchDir.y = 1;
                    }
                    List<Vector2Int> SearchOrigins = new List<Vector2Int>();
                    // 状态查找
                    for (int i = 0; i < SegmentMapState.SizeY; i++)
                    {
                        for (int j = 0; j < SegmentMapState.SizeX; j++)
                        {
                            Vector2Int Origin = new Vector2Int(j, i);

                            // 检查连续查找的合理性
                            Vector2Int End = Origin + (StateFromNode.RuleSegment.AbstructObjectRefs.Length - 1) * SearchDir;
                            if (End.x < 0 || End.x >= SegmentMapState.SizeX || End.y < 0 || End.y >= SegmentMapState.SizeY) { continue; }

                            // 进行查找
                            bool StateCheck = true;
                            for (int k = 0; k < StateFromNode.RuleSegment.AbstructObjectRefs.Length; k++)
                            {
                                var MapElement = SegmentMapState.Map[(i + SearchDir.y * k) * SegmentMapState.SizeX + j + SearchDir.x * k];
                                bool AnyMatch = false;
                                foreach (var ObjectElement in MapElement.Objects)
                                {
                                    if (ObjectElement.Name == StateFromNode.RuleSegment.AbstructObjectRefs[k].Object.Name && ObjectElement.Impulse == StateFromNode.RuleSegment.AbstructObjectRefs[k].Impulse)
                                    {
                                        AnyMatch = true;
                                    }
                                }
                                if (AnyMatch == false)
                                {
                                    StateCheck = false;
                                    break;
                                }
                            }
                            // 装载到可能存在的状态转移
                            if (StateCheck)
                            {
                                var DebugLog = "";
                                DebugLog = "    " + StateFromNode.RuleSegment.ToMermaid() + " --> " + StateToNode.RuleSegment.ToMermaid();
                                switch (StateEdge.ActiveType)
                                {
                                    case EdgeActiveType.Rule: DebugLog += ": Rule"; break;
                                    case EdgeActiveType.Match: DebugLog += ": Match"; break;
                                    case EdgeActiveType.Up: DebugLog += ": W"; break;
                                    case EdgeActiveType.Down: DebugLog += ": S"; break;
                                    case EdgeActiveType.Left: DebugLog += ": A"; break;
                                    case EdgeActiveType.Right: DebugLog += ": D"; break;
                                    case EdgeActiveType.None: DebugLog += ": None"; break;
                                }
                                Debug.Log(DebugLog);
                                SearchOrigins.Add(Origin);
                            }
                        }
                    }

                    if (SearchOrigins.Count > 0)
                    {
                        // 状态转移
                        for (int OriginIndex = 0; OriginIndex < SearchOrigins.Count; OriginIndex++)
                        {
                            Vector2Int Origin = SearchOrigins[OriginIndex];

                            for (int k = 0; k < StateFromNode.RuleSegment.AbstructObjectRefs.Length; k++)
                            {
                                var MapElement = SegmentMapState.Map[(Origin.y + SearchDir.y * k) * SegmentMapState.SizeX + Origin.x + SearchDir.x * k];
                                foreach (var ObjectElement in MapElement.Objects)
                                {
                                    if (ObjectElement.Name == StateFromNode.RuleSegment.AbstructObjectRefs[k].Object.Name && ObjectElement.Impulse == StateFromNode.RuleSegment.AbstructObjectRefs[k].Impulse)
                                    {
                                        //Debug.Log("Change Impulse :" + ObjectElement.Name + " " + StateFromNode.ObjectRefs[k].Object.Name);
                                        ObjectElement.Impulse = StateToNode.RuleSegment.AbstructObjectRefs[k].Impulse;
                                    }
                                }
                            }
                        }
                        SolveNode.Enqueue(NextQueueNode);
                    }
                }
            }

            FrameMapState = (MapState)SegmentMapState.Clone();
        }

        Debug.Log("Total Solve Step: " + SolveStep);
    }
}
